/********************************** (C) COPYRIGHT *******************************
* File Name          : UART.C
* Author             : WCH
* Version            : V1.01
* Date               : 2022/12/13
* Description        : uart serial port related initialization and processing
*******************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for 
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/

#include <USB_Device/usb_com.h>

volatile UART_CTL Uart;

__attribute__ ((aligned(4)))     uint8_t TXFIFO[TXLENGTH];
__attribute__ ((aligned(4)))     uint8_t RXFIFO[RXLENGTH];

/*******************************************************************************/
/* Variable Definition */
/* Global */

/* The following are serial port transmit and receive related variables and buffers */

void disable_swd(void){
    Delay_Ms(1000);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);

    GPIO_InitTypeDef  GPIO_InitStructure  = {0};

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init( GPIOA, &GPIO_InitStructure );

}

/*********************************************************************
 * @fn      TIM2_Init
 *
 * @brief   100us Timer
 *          144 * 100 * 13.8888 -----> 100uS
 *
 * @return  none
 */
void TIM2_Init( void )
{

    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure = {0};

    TIM_DeInit( TIM2 );

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = 100 - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure );

    /* Clear TIM2 update pending flag */
    TIM_ClearFlag( TIM2, TIM_FLAG_Update );

    /* TIM IT enable */
    TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );

    /* Enable Interrupt */
    NVIC_EnableIRQ( TIM2_IRQn );

    /* TIM2 enable counter */
    TIM_Cmd( TIM2, ENABLE );
}

void cdc_transmit(uint16_t length){

    uint16_t Len = length;

    uint32_t remain_len;
    uint16_t packlen;
    uint16_t LastPos = 0;

    Uart.Rx_TimeOut = 0x00;

    /* Serial port 1 data DMA receive processing */
    NVIC_DisableIRQ( USBFS_IRQn );
    NVIC_DisableIRQ( USBFS_IRQn );

    remain_len = Len;

    NVIC_EnableIRQ( USBFS_IRQn );

    Resend:

    if(remain_len){
        if( Uart.USB_Up_IngFlag == 0 )
        {
            packlen = 0;

            if( remain_len >= DEF_USBD_FS_PACK_SIZE ){

                packlen = DEF_USBD_FS_PACK_SIZE;
            }
            else{

                packlen = remain_len;
            }

            if(packlen){

                NVIC_DisableIRQ( USBFS_IRQn );
                NVIC_DisableIRQ( USBFS_IRQn );
                Uart.USB_Up_IngFlag = 0x01;
                Uart.USB_Up_TimeOut = 0x00;
                USBFS_Endp_DataUp( DEF_UEP3, &TXFIFO[ LastPos ], packlen, DEF_UEP_CPY_LOAD );

                LastPos += packlen;
                remain_len -= packlen;

                /* Start 0-length packet timeout timer */
                if( packlen == DEF_USBD_FS_PACK_SIZE )
                {
                    Uart.USB_Up_Pack0_Flag = 0x01;
                }

                NVIC_EnableIRQ( USBFS_IRQn );
            }
        }
        else
        {
            /* Set the upload success flag directly if the upload is not successful after the timeout */
            if( Uart.USB_Up_TimeOut >= DEF_UARTx_USB_UP_TIMEOUT )
            {
                Uart.USB_Up_IngFlag = 0x00;
                USBFS_Endp_Busy[ DEF_UEP3 ] = 0;
            }
        }
    }

    /*****************************************************************/
    /* Determine if a 0-length packet needs to be uploaded (required for CDC mode) */
    if( Uart.USB_Up_Pack0_Flag )
    {
        if( Uart.USB_Up_IngFlag == 0 )
        {
            if( Uart.USB_Up_TimeOut >= ( DEF_UARTx_RX_TIMEOUT * 20 ) )
            {
                NVIC_DisableIRQ( USBFS_IRQn );
                NVIC_DisableIRQ( USBFS_IRQn );
                Uart.USB_Up_IngFlag = 0x01;
                Uart.USB_Up_TimeOut = 0x00;
                USBFS_Endp_DataUp( DEF_UEP3, &TXFIFO[ LastPos ], 0, DEF_UEP_CPY_LOAD );
                Uart.USB_Up_IngFlag = 0;
                Uart.USB_Up_Pack0_Flag = 0x00;
                NVIC_EnableIRQ( USBFS_IRQn );
            }
        }
    }

    if(remain_len){
        goto Resend;
    }

}


